#ifndef __FOR__HPP__
#define __FOR__HPP__

template <class A, class B, int PLACE>
constexpr std::pair<Expression<A>, Expression<B>>
FOR(const VariableTerm<PLACE> &, Expression<A> const & a, Expression<B> const & b) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<Expression<A>, Expression<B>> (a.expr_, b.expr_);
}

// The following case captures (VariableTerm, expr)
template <class B, int PLACE, int PLACE2>
constexpr std::pair<VariableTerm<PLACE2>, Expression<B>>
FOR(const VariableTerm<PLACE> &, const VariableTerm<PLACE2> &a, Expression<B> const & b) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<VariableTerm<PLACE2>, Expression<B>> (a, b.expr_);
}

// The following case captures (expr, VariableTerm)
template <class B, int PLACE, int PLACE2>
constexpr std::pair<Expression<B>, VariableTerm<PLACE2>>
FOR(const VariableTerm<PLACE> &, Expression<B> const & b, const VariableTerm<PLACE2> &a) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<Expression<B>, VariableTerm<PLACE2>> (b.expr_, a);
}

// The following case captures (VariableTerm, VariableTerm)
template <int PLACE, int PLACE2, int PLACE3>
constexpr std::pair<VariableTerm<PLACE2>, VariableTerm<PLACE3>>
FOR(const VariableTerm<PLACE> &, const VariableTerm<PLACE2> &a, const VariableTerm<PLACE3> &b) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<VariableTerm<PLACE2>, VariableTerm<PLACE3>> (a, b);
}

// The following case captures (int, expr)
template <class B, int PLACE>
constexpr std::pair<ConstantTerm, Expression<B>>
FOR(const VariableTerm<PLACE> &, int a, Expression<B> const & b) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<ConstantTerm, Expression<B>> ((ConstantTerm)a, b.expr_);
}

// The following case captures (expr, int)
template <class B, int PLACE>
constexpr std::pair<Expression<B>, ConstantTerm>
FOR(const VariableTerm<PLACE> &, Expression<B> const & b, int a) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<Expression<B>, ConstantTerm> (b.expr_, (ConstantTerm)a);
}

// The following case captures (VariableTerm, int)
template <int PLACE, int PLACE2>
constexpr std::pair<VariableTerm<PLACE2>, ConstantTerm>
FOR(const VariableTerm<PLACE> &, const VariableTerm<PLACE2> &a, int b) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<VariableTerm<PLACE2>, ConstantTerm> (a, (ConstantTerm)b);
}

// The following case captures (int, VariableTerm)
template <int PLACE, int PLACE2>
constexpr std::pair<ConstantTerm, VariableTerm<PLACE2>>
FOR(const VariableTerm<PLACE> &, int b, const VariableTerm<PLACE2> &a) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<ConstantTerm, VariableTerm<PLACE2>> ((ConstantTerm)b, a);
}

// The following case captures (int, int)
template <int PLACE>
constexpr std::pair<ConstantTerm, ConstantTerm>
FOR(const VariableTerm<PLACE> &, int a, int b) {
  // static_assert(t.getPlace() >= 0, "PLACES MUST BE >= 0 !");
  return std::pair<ConstantTerm, ConstantTerm> ((ConstantTerm)a, (ConstantTerm)b);
}
#endif //__FOR__HPP__
